<?php
namespace app\system\controller;

use app\BaseController;
use think\facade\Cache;
use think\Facade\Db;

class Database extends BaseController
{
    public function index()
    {
        $type = input('post.type');
        if ($type == 'tables') {
            $datas = Db::query('SHOW TABLE STATUS');
            $datas = array_map('array_change_key_case', $datas);
        } else {
            $datas = $this->files();
        }

        return ['code' => 0, 'datas' => $datas];
    }

    public function config()
    {
        if (request()->isPost()) {
            $field = input('post.field');
            $path = app_path() . 'config/backup.php';
            $code = <<<EOT
<?php
return [
    'path' => '{$field['path']}',
    'size' => {$field['size']}
];
EOT;

            $res = file_put_contents($path, $code);
            if ($res) {
                return ['code' => 0, 'message' => '编辑配置成功！'];
            } else {
                return ['code' => 1, 'message' => '编辑配置失败！'];
            }
        } else {
            $datas = config('backup');
            return ['code' => 0, 'datas' => $datas];
        }
    }

    protected function files()
    {
        $config = config('backup');
        $path = root_path() . $config['path'];
        $list = scandir($path);
        $datas = $data = [];
        foreach ($list as $item) {
            if ($item == '.' || $item == '..') {
                continue;
            }

            $file = $path . '/' . $item;
            $isDir = is_dir($file);

            if (!$isDir) {
                continue;
            }

            $files = scandir($file);
            $data['count'] = 0;
            $data['size'] = 0;
            foreach ($files as $value) {
                if ($value == '.' || $value == '..') {
                    continue;
                }
                //print_r();die;
                $filePath = $file . '/' . $value;
                if (is_file($filePath) || strpos($value, '.sql') == false) {
                    $data['count']++;
                    $data['size'] = $data['size'] + filesize($filePath);
                }
            }

            $data['name'] = $item;
            $data['ctime'] = filectime($file);
            $data['mtime'] = filemtime($file);
            $data['readable'] = is_readable($file);
            $data['writable'] = is_writable($file);
            $data['executable'] = is_executable($file);
            $datas[] = $data;
        }
        return $datas;
    }

    public function repair()
    {
        $tables = input('post.tables');
        if (is_array($tables)) {
            $tables = implode('`,`', $tables);
        }

        $res = Db::execute("REPAIR TABLE `$tables`");
        if ($res) {
            return ['code' => 0, 'message' => '修复完成！'];
        } else {
            return ['code' => 1, 'message' => '修复失败！'];
        }
    }

    public function optimize()
    {
        $tables = input('post.tables');
        if (is_array($tables)) {
            $tables = implode('`,`', $tables);
        }

        $res = Db::execute("OPTIMIZE TABLE `$tables`");

        if ($res) {
            return ['code' => 0, 'message' => '优化完成！'];
        } else {
            return ['code' => 1, 'message' => '优化失败！'];
        }
    }

    public function backup()
    {
        $tables = Db::getTables();
        $database = config('database.connections.mysql');
        $version = PHP_VERSION;
        $time = date('Y-m-d h:i:s', time());
        $mysql = Db::query('select VERSION() as version');

        $code = <<<EOT
-- 主机： {$database['hostname']}
-- 生成日期： $time
-- Mysql 版本： {$mysql[0]['version']}
-- PHP 版本： $version

--
-- 数据库： `{$database['database']}`
--

SET FOREIGN_KEY_CHECKS = 0;

EOT;

        $this->writeFile($code);

        foreach ($tables as $key => $table) {
            $result = Db::query("SHOW CREATE TABLE `$table`");

            $create = trim($result[0]['Create Table']);
            $create = str_replace(["\r\n", "\r", "\n", '  '], '', $create);

            $code = <<<EOT

--
-- 表 `$table` 结构
--

DROP TABLE IF EXISTS `{$table}`;

$create;

--
-- 表 `$table` 数据
--

EOT;
            $size = count($tables);
            $progress = (100 / $size) * ($key + 1);

            Cache::tag('status')->set('table', $table);
            Cache::tag('status')->set('progress', $progress);
            $this->writeFile($code);
            $datas = Db::table($table)->select();
            //sleep(10);

            foreach ($datas as $data) {
                $sql = Db::table($table)->fetchSql(true)->insert($data);
                $this->writeFile($sql . ";\r\n");
            }
        }

        Cache::delete('name');
        Cache::delete('dir');
    }

    public function progress()
    {
        if (Cache::getTagItems('status')) {
            $datas = [
                'table' => Cache::get('table'),
                'progress' => (int) Cache::get('progress'),
            ];

            if ($datas['progress'] == '100') {
                Cache::tag('status')->clear();
            }
            return ['code' => 0, 'datas' => $datas];
        } else {
            return ['code' => 1, 'message' => '没有进行备份！'];
        }
    }

    protected function writeFile($code)
    {
        $config = config('backup');
        $name = Cache::remember('name', 1);
        $dir = Cache::remember('dir', time());
        $path = root_path() . $config['path'] . '/' . $dir . '/' . $name . '.sql';

        if (file_exists($path)) {
            $size = filesize($path);
            if ($size >= $config['size']) {
                Cache::inc('name');
                $name = Cache::get('name');
                $path = root_path() . $config['path'] . '/' . $dir . '/' . $name . '.sql';
            }
        }

        $this->checkPath(dirname($path));
        return file_put_contents($path, $code, FILE_APPEND);
    }

    protected function checkPath($path)
    {
        if (is_dir($path)) {
            return true;
        }
        if (mkdir($path, 0755, true)) {
            return true;
        } else {
            return false;
        }
    }

    public function delete()
    {
        $name = input('post.name');
        $config = config('backup');
        $path = root_path() . $config['path'] . '/' . $name;
        $res = $this->deleteFile($path);
        if ($res) {
            return ['code' => 0, 'message' => '删除完成！'];
        } else {
            return ['code' => 1, 'message' => '删除失败！'];
        }
    }

    protected function deleteFile($path)
    {
        if (is_file($path)) {
            return unlink($path);
        }

        $list = scandir($path);

        foreach ($list as $item) {
            if ($item == '.' || $item == '..') {
                continue;
            }
            $_path = $path . '/' . $item;
            if (is_dir($_path)) {
                $this->deleteFile($_path);
            } else {
                unlink($_path);
            }
        }

        return rmdir($path);
    }

    public function restore()
    {
        $name = input('post.name');
        $config = config('backup');
        $path = root_path() . $config['path'] . '/' . $name;
        $list = scandir($path);
        foreach ($list as $item) {
            if ($item == '.' || $item == '..') {
                continue;
            }

            $file = $path . '/' . $item;

            if (strpos($file, '.sql') == false) {
                continue;
            }
            $content = file_get_contents($file);

            preg_match_all('/.*;/', trim($content), $matches);

            foreach ($matches[0] as $sql) {
                $res = Db::execute($sql);
            }
        }

        return ['code' => 0, 'message' => '恢复完成！'];
    }

}
